package smallfrench.moteur.biblio;

import java.util.Iterator;

import smallfrench.moteur.biblio.err.ErreurClasse;
import smallfrench.moteur.interp.RObjet;

public abstract class AIterable extends AObjet {

	public static final AClasse CLASSE = AClasse.creer(
			AIterable.class, "Iterable");

	@AnnotationMembre
	public AIterable() {
	}

	/**
	 * 
	 * @return Un itérateur
	 */
	@AnnotationMembre
	public abstract AIterateur iterateur();

	@Override
	@AnnotationMembre
	public RChaine enChaine() {
		return new RChaine("Iterable");
	}

	public final static Iterator<RObjet> getIterateur(RObjet iterable) {

		final RObjet[] tabVide = new RObjet[0];

		if (! iterable.classe.estUne(AIterable.CLASSE)) {
			throw ErreurClasse.nouvelleException(iterable, AIterable.CLASSE);
		}

		final RObjet fnIterateur = iterable.getMembre("iterateur");
		final RObjet iterateur = fnIterateur.appeler(iterable, tabVide);
		final RObjet fnSuivant = iterateur.getMembre("suivant");
		final RObjet fnContientAutres = iterateur.getMembre("contientAutres");

		if (! iterateur.classe.estUne(AIterateur.CLASSE)) {
			throw ErreurClasse.nouvelleException(iterable, AIterateur.CLASSE);
		}

		return new Iterator<RObjet>() {

			@Override
			public boolean hasNext() {
				RObjet r = fnContientAutres.appeler(iterateur, tabVide);
				if (! (r instanceof RBooleen)) {
					throw ErreurClasse.nouvelleException(
							r, RClasseBooleen.CLASSE);
				}
				return ((RBooleen) r).valeur;
			}

			@Override
			public RObjet next() {
				return fnSuivant.appeler(iterateur, tabVide);
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
}
